Using *args and **kwargs in Python
Course: Python Training
Topic: Using *args and **kwargs
Course Link: Python Training Course
Demo Link: Register for a Free Course Demo
Website: JustAcademy
1. Introduction to *args and **kwargs
In Python, functions can accept inputs through parameters. Sometimes, however, we do not know in advance how many values a function will receive. Python provides *args and **kwargs to handle a flexible number of arguments.
*args allows a function to accept any number of positional arguments, while **kwargs allows it to accept any number of keyword arguments. These features are especially useful when building reusable functions, utility methods, decorators, APIs, and configurable programs.
Learning Objectives
- Understand positional and keyword arguments.
- Learn how
*args collects multiple positional arguments.
- Learn how
**kwargs collects multiple keyword arguments.
- Use both features together in a function.
- Understand argument unpacking with
* and **.
- Identify common errors and apply best practices.
2. Understanding Function Arguments
Arguments are the values passed to a function when it is called. Parameters are the variable names written in the function definition to receive those values.
def greet(name, message):
print(message, name)
greet("Aarav", "Hello")
Output:
Hello Aarav
In this example, name and message are parameters, while "Aarav" and "Hello" are arguments.
Types of Arguments
| Type |
Description |
Example |
| Positional |
Values are matched according to their position. |
greet("Aarav", "Hello") |
| Keyword |
Values are passed using parameter names. |
greet(name="Aarav", message="Hello") |
| Default |
A parameter uses a predefined value when no argument is supplied. |
def greet(name="Guest"): |
| Variable-length positional |
A function receives any number of positional arguments. |
def add(*args): |
| Variable-length keyword |
A function receives any number of keyword arguments. |
def profile(**kwargs): |
3. What Is *args?
*args is used in a function definition to accept a variable number of positional arguments. Python collects the extra positional arguments into a tuple.
The name args is a convention, not a reserved keyword. You could use another valid name, such as *numbers, but *args is widely understood and commonly used.
Syntax
def function_name(*args):
# Process the collected arguments
pass
Example 1: Display Multiple Values
def show_values(*args):
print(args)
show_values(10, 20, 30)
show_values("Python", "Java", "SQL")
show_values()
Output:
(10, 20, 30)
('Python', 'Java', 'SQL')
()
The function accepts different numbers and types of values. All positional arguments are collected into a tuple, including an empty tuple when no arguments are supplied.
Example 2: Add Any Number of Numbers
def add_numbers(*args):
total = 0
for number in args:
total += number
return total
print(add_numbers(10, 20))
print(add_numbers(5, 10, 15, 20))
print(add_numbers(100, 200, 300, 400, 500))
Output:
30
50
1500
Explanation: The function loops through every value stored in args and adds it to total. The number of supplied arguments can change without requiring a new function definition.
Example 3: Find the Highest Value
def find_maximum(*args):
if not args:
return None
return max(args)
print(find_maximum(12, 45, 8, 67, 23))
print(find_maximum(100, 200, 150))
print(find_maximum())
Output:
67
200
None
The empty-input check prevents the function from calling max() on an empty tuple, which would raise a ValueError.
4. What Is **kwargs?
**kwargs allows a function to receive a variable number of keyword arguments. Python collects these arguments into a dictionary, where each keyword becomes a key and its value becomes the corresponding dictionary value.
The name kwargs is a convention meaning “keyword arguments.” The double asterisk is the important syntax.
Syntax
def function_name(**kwargs):
# Process the collected keyword arguments
pass
Example 1: Display Keyword Arguments
def show_details(**kwargs):
print(kwargs)
show_details(name="Aarav", age=22)
show_details(course="Python", duration="3 months")
show_details()
Output:
{'name': 'Aarav', 'age': 22}
{'course': 'Python', 'duration': '3 months'}
{}
Each keyword argument is stored as a key-value pair. If no keyword arguments are supplied, kwargs is an empty dictionary.
Example 2: Print a User Profile
def display_profile(**kwargs):
for key, value in kwargs.items():
print(f"{key}: {value}")
display_profile(
name="Meera",
age=24,
city="Mumbai",
skill="Python"
)
Output:
name: Meera
age: 24
city: Mumbai
skill: Python
The items() method provides each key and its associated value, making it useful for displaying flexible sets of details.
Example 3: Access Specific Keyword Values
def student_details(**kwargs):
print("Name:", kwargs.get("name", "Not provided"))
print("Course:", kwargs.get("course", "Not provided"))
print("City:", kwargs.get("city", "Not provided"))
student_details(name="Riya", course="Python")
Output:
Name: Riya
Course: Python
City: Not provided
The dictionary method get() lets you retrieve a value safely and specify a fallback when a key is missing.
5. Difference Between *args and **kwargs
| Feature |
*args |
**kwargs |
| Purpose |
Accepts extra positional arguments. |
Accepts extra keyword arguments. |
| Collection type |
Tuple |
Dictionary |
| Calling style |
function(10, 20, 30) |
function(name="Riya", age=22) |
| Access method |
By index or iteration. |
By key or dictionary methods. |
| Typical use |
Variable lists of values, totals, or calculations. |
Flexible configuration and named details. |
| Symbol |
One asterisk: * |
Two asterisks: ** |
Quick Comparison Example
def example(*args, **kwargs):
print("Positional:", args)
print("Keyword:", kwargs)
example(10, 20, 30, name="Aarav", city="Pune")
Output:
Positional: (10, 20, 30)
Keyword: {'name': 'Aarav', 'city': 'Pune'}
6. Using *args and **kwargs Together
A function can use both features when it needs to accept positional values and named options. The usual parameter order places ordinary parameters first, followed by *args, then keyword-only parameters if any, and finally **kwargs.
Example 1: Flexible Student Information
def student_info(student_name, *subjects, **details):
print("Student:", student_name)
print("Subjects:", subjects)
print("Additional Details:", details)
student_info(
"Aarav",
"Python",
"SQL",
"HTML",
age=21,
city="Mumbai",
level="Beginner"
)
Output:
Student: Aarav
Subjects: ('Python', 'SQL', 'HTML')
Additional Details: {'age': 21, 'city': 'Mumbai', 'level': 'Beginner'}
Explanation:
student_name receives the first positional value.
subjects collects the remaining positional values into a tuple.
details collects the named arguments into a dictionary.
Example 2: Product Order Summary
def order_summary(product, quantity, *extras, **options):
print("Product:", product)
print("Quantity:", quantity)
print("Extras:", extras)
print("Options:", options)
order_summary(
"Laptop",
1,
"Mouse",
"Laptop Bag",
delivery="Express",
payment="Card",
gift_wrap=True
)
Output:
Product: Laptop
Quantity: 1
Extras: ('Mouse', 'Laptop Bag')
Options: {'delivery': 'Express', 'payment': 'Card', 'gift_wrap': True}
This structure is useful when a function has required inputs but should also allow optional add-ons and configurable settings.
7. Argument Unpacking with * and **
The asterisk symbols can also be used when calling a function. This is called argument unpacking. It allows values in an iterable or dictionary to be passed as individual arguments.
Unpacking a List or Tuple with *
def multiply(a, b, c):
return a * b * c
numbers = [2, 3, 4]
print(multiply(*numbers))
Output:
24
*numbers unpacks the list into three positional arguments, equivalent to multiply(2, 3, 4).
Unpacking a Dictionary with **
def display_user(name, age, city):
print(f"{name} is {age} years old and lives in {city}.")
user = {
"name": "Meera",
"age": 24,
"city": "Mumbai"
}
display_user(**user)
Output:
Meera is 24 years old and lives in Mumbai.
The dictionary keys must match the function's parameter names unless the function accepts additional keyword arguments through **kwargs.
Collecting and Unpacking Are Different
| Syntax |
Where used |
Meaning |
def f(*args): |
Function definition |
Collects extra positional arguments into a tuple. |
f(*values) |
Function call |
Unpacks an iterable into positional arguments. |
def f(**kwargs): |
Function definition |
Collects extra keyword arguments into a dictionary. |
f(**settings) |
Function call |
Unpacks a mapping into keyword arguments. |
8. Real-World Example: Shopping Cart Total
A shopping cart may contain different numbers of item prices. The following example uses *args to calculate the subtotal and **kwargs to accept optional order settings.
def calculate_cart_total(*prices, **options):
subtotal = sum(prices)
discount = options.get("discount", 0)
delivery_fee = options.get("delivery_fee", 0)
if not 0 <= discount <= 100:
raise ValueError("Discount must be between 0 and 100.")
discounted_total = subtotal * (1 - discount / 100)
final_total = discounted_total + delivery_fee
print("Subtotal:", subtotal)
print("Discount:", discount, "%")
print("Delivery Fee:", delivery_fee)
print("Final Total:", round(final_total, 2))
calculate_cart_total(
500,
250,
150,
discount=10,
delivery_fee=40
)
Output:
Subtotal: 900
Discount: 10 %
Delivery Fee: 40
Final Total: 850.0
How it works:
*prices collects the item prices into a tuple.
sum(prices) calculates the subtotal.
options.get() reads optional settings and provides defaults.
- The function checks that the discount percentage is valid.
- The final amount is calculated after applying the discount and delivery fee.
9. Real-World Example: Configurable Employee Record
When employee records have different optional fields, **kwargs can collect additional details without requiring a separate parameter for every possible field.
def create_employee(name, role, **details):
employee = {
"name": name,
"role": role
}
employee.update(details)
return employee
record = create_employee(
"Neha",
"Data Analyst",
department="Analytics",
location="Mumbai",
experience=2,
remote=True
)
print(record)
Output:
{'name': 'Neha', 'role': 'Data Analyst', 'department': 'Analytics', 'location': 'Mumbai', 'experience': 2, 'remote': True}
This approach is convenient for flexible data structures. In production applications, validate allowed field names and value types when correctness or security matters.
10. Using *args with a Regular Parameter
You can define required parameters before *args. Those parameters receive their expected values, and any additional positional values are collected in the tuple.
def calculate_average(label, *numbers):
if not numbers:
print(label, "No numbers supplied")
return
average = sum(numbers) / len(numbers)
print(label, round(average, 2))
calculate_average("Test Average:", 80, 90, 85)
calculate_average("Exam Average:", 70, 75, 95, 100)
calculate_average("Empty Average:")
Output:
Test Average: 85.0
Exam Average: 85.0
Empty Average: No numbers supplied
The required label parameter is handled separately from the variable number of scores.
11. Keyword-Only Parameters
Python allows parameters to be made keyword-only by placing them after a bare asterisk or after *args. These parameters must be supplied using their names. This helps make function calls more readable and reduces confusion between similar values.
def create_account(username, *roles, active=True):
print("Username:", username)
print("Roles:", roles)
print("Active:", active)
create_account("riya", "editor", "reviewer", active=False)
Output:
Username: riya
Roles: ('editor', 'reviewer')
Active: False
Here, active is keyword-only because it appears after *roles. Calling create_account("riya", "editor", "reviewer", False) would raise a TypeError because the final value is not allowed positionally.
12. Common Errors and How to Fix Them
Error 1: Passing Too Many Positional Arguments
def greet(name):
print("Hello", name)
greet("Riya", "Meera")
Problem: The function accepts one positional argument but receives two, causing a TypeError.
Solution: If multiple values are intended, use *args or change the function's parameters.
def greet(*names):
for name in names:
print("Hello", name)
greet("Riya", "Meera")
Error 2: Passing an Unexpected Keyword
def show_name(name):
print(name)
show_name(name="Riya", city="Mumbai")
Problem: The function does not define a city parameter and does not accept extra keywords.
Solution: Add a city parameter if it is required, or use **kwargs when additional keyword values are appropriate.
def show_name(name, **details):
print(name)
print(details)
show_name(name="Riya", city="Mumbai")
Error 3: Confusing a Tuple with Separate Values
def display(*args):
print(args)
display([10, 20, 30])
Output:
([10, 20, 30],)
Explanation: The list is one positional argument, so the tuple contains one item: that list. To pass its elements separately, use display(*[10, 20, 30]), which produces (10, 20, 30).
Error 4: Incorrect Parameter Order
# Incorrect
def example(**kwargs, *args):
pass
Problem: Variable positional arguments must appear before variable keyword arguments in a function signature.
Correct version:
def example(*args, **kwargs):
pass
Error 5: Duplicate Values for the Same Parameter
def greet(name):
print(name)
greet("Riya", name="Meera")
Problem: The parameter name receives a value positionally and again by keyword, so Python raises a TypeError.
Solution: Supply each parameter only once.
13. Best Practices for *args and **kwargs
- Use
*args when a function genuinely needs a variable number of positional values.
- Use
**kwargs for flexible named options or additional fields.
- Prefer explicit parameters for required inputs because they make a function easier to understand.
- Use clear, descriptive names when the context is complex, even though
args and kwargs are conventional.
- Validate inputs before performing calculations or updating data.
- Use dictionary methods such as
get() when optional keyword values may be absent.
- Document what extra arguments a function accepts, including expected types and defaults.
- Avoid accepting arbitrary keyword arguments when they could hide spelling mistakes or invalid options.
- Remember that
*args creates a tuple and **kwargs creates a dictionary.
- Keep function signatures readable and avoid using flexible arguments when a fixed set of parameters is clearer.
14. Practice Exercises
Exercise 1: Sum All Values
Create a function named sum_all() that accepts any number of numeric arguments and returns their sum.
def sum_all(*args):
return sum(args)
print(sum_all(10, 20, 30))
print(sum_all(5, 15, 25, 35))
Expected Output:
60
80
Exercise 2: Display Book Details
Create a function that accepts a book title and any number of additional keyword details.
def book_details(title, **details):
print("Title:", title)
for key, value in details.items():
print(f"{key}: {value}")
book_details(
"Learning Python",
author="Example Author",
level="Beginner",
format="Paperback"
)
Expected Output:
Title: Learning Python
author: Example Author
level: Beginner
format: Paperback
Exercise 3: Calculate a Discounted Total
Write a function that receives any number of prices through *args and a named discount percentage through **kwargs.
def discounted_total(*prices, **options):
discount = options.get("discount", 0)
if not 0 <= discount <= 100:
raise ValueError("Discount must be between 0 and 100.")
total = sum(prices)
return round(total * (1 - discount / 100), 2)
print(discounted_total(100, 200, 300, discount=10))
print(discounted_total(50, 50))
Expected Output:
540.0
100.0
Exercise 4: Combine Positional and Keyword Arguments
Create a function that accepts a person's name, several skills, and extra profile details.
def profile(name, *skills, **details):
print("Name:", name)
print("Skills:", ", ".join(skills))
print("Details:", details)
profile(
"Karan",
"Python",
"SQL",
"Power BI",
city="Pune",
experience=1
)
Expected Output:
Name: Karan
Skills: Python, SQL, Power BI
Details: {'city': 'Pune', 'experience': 1}
15. Interview Questions and Answers
Q1. What is *args in Python?
Answer: *args allows a function to accept any number of positional arguments. Python collects those values into a tuple.
Q2. What is **kwargs in Python?
Answer: **kwargs allows a function to accept any number of keyword arguments. Python collects them into a dictionary.
Q3. Are args and kwargs Python keywords?
Answer: No. They are conventional names. The important syntax is the single asterisk for variable positional arguments and the double asterisk for variable keyword arguments.
Q4. Can *args and **kwargs be used in the same function?
Answer: Yes. For example, def example(*args, **kwargs): can collect positional and keyword arguments separately.
Q5. What data type does *args create?
Answer: A tuple.
Q6. What data type does **kwargs create?
Answer: A dictionary.
Q7. What is argument unpacking?
Answer: Argument unpacking uses * to pass elements of an iterable as positional arguments or ** to pass mapping entries as keyword arguments.
Q8. Can a function have normal parameters before *args?
Answer: Yes. Required or ordinary parameters can appear before *args, and the remaining positional arguments are collected into a tuple.
Q9. When should you avoid using **kwargs?
Answer: Avoid it when a fixed, clearly defined set of parameters is more suitable, or when accepting arbitrary keys could hide mistakes and invalid options.
Q10. What happens if no arguments are supplied?
Answer: If no extra positional values are supplied, args is an empty tuple. If no extra keyword values are supplied, kwargs is an empty dictionary.
16. Quick Revision Checklist
*args collects extra positional arguments into a tuple.
**kwargs collects extra keyword arguments into a dictionary.
- Use
*iterable to unpack values into positional arguments.
- Use
**mapping to unpack key-value pairs into keyword arguments.
- Both can be used in the same function.
- Required parameters can appear before variable-length parameters.
- Keyword-only parameters can appear after
*args.
- Validate inputs and document supported options.
- Use explicit parameters whenever they make the function clearer.
17. Conclusion
*args and **kwargs make Python functions flexible by supporting a variable number of positional and keyword arguments. They are useful for reusable utilities, configurable functions, data-processing workflows, and applications where optional inputs vary from one call to another.
To master these concepts, practise writing functions that calculate totals, display profiles, process optional settings, and unpack lists and dictionaries into function calls. Choose flexible arguments when they solve a real problem, and keep function interfaces clear and well documented.
Continue Learning: Explore the Python Training Course, register for a course demo, or visit the JustAcademy website.